﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using Magellan.Controls.Conventions;
using Magellan.Controls.Conventions.Editors;

namespace Magellan.Controls
{
    /// <summary>
    /// A control that contains a collection of fields.
    /// </summary>
    [StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(Form))]
    public class Form : ItemsControl
    {
        /// <summary>
        /// Dependency property for the FieldBuilder property.
        /// </summary>
        public static readonly DependencyProperty FieldBuilderProperty = DependencyProperty.RegisterAttached("FieldBuilder", typeof(IFieldConvention), typeof(Form), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));

        /// <summary>
        /// Initializes the <see cref="Form"/> class.
        /// </summary>
        static Form()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(Form), new FrameworkPropertyMetadata(typeof(Form)));
        }

        /// <summary>
        /// Dependency property for the IsReadOnly property
        /// </summary>
        public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.RegisterAttached("IsReadOnly",
                        typeof(bool),
                        typeof(Form),
                        new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits, ReadOnlyChanged));

        /// <summary>
        /// Checks if a form or field is read only
        /// </summary>
        /// <param name="form"></param>
        /// <returns></returns>
        public static bool GetIsReadOnly(DependencyObject form)
        {
            return (bool)form.GetValue(IsReadOnlyProperty);
        }

        /// <summary>
        /// Sets a form and all controls in it to be read only
        /// </summary>
        /// <param name="form"></param>
        /// <param name="isReadonly"></param>
        public static void SetIsReadOnly(DependencyObject form, bool isReadonly)
        {
            form.SetValue(IsReadOnlyProperty, isReadonly);
        }

        private static void ReadOnlyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var form = d as Form;
            if (form != null)
            {
                if ((bool)e.NewValue)
                    SetFieldBuilder(d, new FieldConvention(ReadOnlyStrategies));
                else
                    SetFieldBuilder(d, null);
            }

            var field = d as Field;
            if (field != null)
            {
                if (GetIsReadOnly(field) != (bool)e.NewValue)
                    field.Dispatcher.BeginInvoke(DispatcherPriority.DataBind, (Action)field.InvalidateField);
            }
        }

        /// <summary>
        /// Gets the field builder associated with the given element.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        public static IFieldConvention GetFieldBuilder(DependencyObject element)
        {
            return (IFieldConvention)element.GetValue(FieldBuilderProperty);
        }

        /// <summary>
        /// Sets the field builder associated with the given element.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="value">The value.</param>
        public static void SetFieldBuilder(DependencyObject element, IFieldConvention value)
        {
            element.SetValue(FieldBuilderProperty, value);
        }

        private static readonly EditorStrategyCollection readOnlyEditors = new EditorStrategyCollection(new ReadOnlyEditorStrategy());

        /// <summary>
        /// Readonly editor strategies
        /// </summary>
        public static EditorStrategyCollection ReadOnlyStrategies
        {
            get { return readOnlyEditors; }
        }
    }
}
